package awk.etl.function.register;

import awk.etl.dataset.DataSetExecuteMock;
import awk.etl.model.FunctionBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Random;

/***
 * 函数执行引擎
 */
public class FunctionExecute {
    protected static final Log log = LogFactory.getLog(FunctionExecute.class);

    public static void main(String[] args) {
        //Object[] parameters = new Object[]{"123", "abc"};
        List<List<Map<String, Object>>> parameters = Arrays.asList(DataSetExecuteMock.datas[new Random().nextInt(5)],
                DataSetExecuteMock.datas[new Random().nextInt(5)]);
        String methodArg = "ekko.converge_join";
        Object result = executionFunction(methodArg, parameters.toArray());
        System.out.println(result);
    }

    public static Object executionFunction(String methodArg, Object[] paramArgs) {
        String namespace = null;
        String methodName = null;
        String[] split = methodArg.split("\\.");
        if (split.length == 1) {
            namespace = "system";
            methodName = split[0];
        } else {
            namespace = split[0];
            methodName = split[1];
        }
        Object result = null;
        try {
            FunctionBean functionBean = FunctionRegister.nameSpaceAndFunction.get(namespace, methodName);
            if (null == functionBean) {
                log.error("函数:" + methodArg + "不存在");
                throw new ClassNotFoundException("参数异常,函数:" + methodArg + "不存在");
            }
            Method method = functionBean.getMethod();
            if (!validParam(method, paramArgs)) {
                log.error("函数:" + methodArg + "参数错误");
                throw new ClassNotFoundException("函数:" + methodArg + "参数错误");
            }

            Object instance = functionBean.getInstance();
            result = method.invoke(instance, paramArgs);
        } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    /**
     * 参数校验：
     * 1.参数个数校验
     * 2.参数类型校验
     *
     * @param method
     * @param paramArgs 实参
     * @return
     */
    private static Boolean validParam(Method method, Object[] paramArgs) {
        Parameter[] parameters = method.getParameters();
        //可变型参
        if (parameters.length == 1 && parameters[0].getParameterizedType() instanceof GenericArrayTypeImpl) {
            Parameter parameter = parameters[0];
            Class<?> parameterType = parameter.getType();
            log.info("parameterType:" + parameterType);
            //TODO 需要判断参数类型
            return true;
        } else {
            if (parameters.length != paramArgs.length) {
                log.error("参数缺失");
                return false;
            }

            String signature = ReflectUtil.getSignature(method, false);
            for (int i = 0; i < paramArgs.length; i++) {
                //实参
                Class<?> aClass = paramArgs[i].getClass();
                //型参
                Parameter parameter = parameters[i];
                log.info("方法" + signature + "第" + (i + 1) + "个实参类型是" + parameter);
                //范型获取。范型存在嵌套，逐级判断比较复杂，这里只做一级的范型校验
                //Type[] actualTypeArguments = ((ParameterizedTypeImpl) parameter.getParameterizedType()).getActualTypeArguments();
                if (!parameter.getType().isAssignableFrom(aClass)) {
                    log.error("方法" + signature + " 型参和实参校验失败,第" + (i + 1) + "个参数类型错误,期望的参数类型是" + parameter);
                }
            }
            return true;
        }
    }
}
